package com.xuecheng.orders.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.sun.javafx.binding.StringFormatter;
import com.xuecheng.base.exception.XueChengPlusException;
import com.xuecheng.base.utils.IdWorkerUtils;
import com.xuecheng.base.utils.QRCodeUtil;
import com.xuecheng.messagesdk.model.po.MqMessage;
import com.xuecheng.messagesdk.service.MqMessageService;
import com.xuecheng.orders.config.AlipayConfig;
import com.xuecheng.orders.config.PayNotifyConfig;
import com.xuecheng.orders.mapper.XcOrdersGoodsMapper;
import com.xuecheng.orders.mapper.XcOrdersMapper;
import com.xuecheng.orders.mapper.XcPayRecordMapper;
import com.xuecheng.orders.model.dto.AddOrderDto;
import com.xuecheng.orders.model.dto.PayRecordDto;
import com.xuecheng.orders.model.dto.PayStatusDto;
import com.xuecheng.orders.model.po.XcOrders;
import com.xuecheng.orders.model.po.XcOrdersGoods;
import com.xuecheng.orders.model.po.XcPayRecord;
import io.swagger.annotations.ApiOperation;
import jdk.nashorn.internal.scripts.JO;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.message.StringFormattedMessage;
import org.aspectj.weaver.ast.Var;
import org.bouncycastle.jcajce.provider.symmetric.RC2;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;

import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class OrderServiceImpl implements OrderService{
    @Autowired
    XcOrdersMapper ordersMapper;
    @Autowired
    XcOrdersGoodsMapper ordersGoodsMapper;
    @Autowired
    XcPayRecordMapper payRecordMapper;
    @Value("${pay.qrcodeurl}")
    String qrcodeurl;
    @Autowired
    OrderServiceImpl orderServiceImpl;

    @Value("${pay.alipay.APP_ID}")
    String APP_ID;
    @Value("${pay.alipay.APP_PRIVATE_KEY}")
    String APP_PRIVATE_KEY;

    @Value("${pay.alipay.ALIPAY_PUBLIC_KEY}")
    String ALIPAY_PUBLIC_KEY;
    @Autowired
    RabbitTemplate rabbitTemplate;
    @Autowired
    MqMessageService mqMessageService;

    @Transactional
    @Override
    public PayRecordDto createOrder(String userId, AddOrderDto addOrderDto) {
        //添加商品订单
        XcOrders xcOrders = saveXcOrders(userId, addOrderDto);


        //添加交易记录
        XcPayRecord payRecord = createPayRecord(xcOrders);

        //生成二维码
        String qrcode=null;
        try {
            String url = String.format(qrcodeurl, payRecord.getPayNo());
            qrcode=new QRCodeUtil().createQRCode(url,200,200);
        }catch (Exception e){
            XueChengPlusException.cast("生成二维码出错");
        }
        PayRecordDto payRecordDto = new PayRecordDto();
        BeanUtils.copyProperties(payRecord,payRecordDto);
        payRecordDto.setQrcode(qrcode);

        return payRecordDto;
    }

    @Transactional
    public XcOrders saveXcOrders(String userId, AddOrderDto addOrderDto){
        //插入订单,需要进行幂等性判断
        XcOrders orders = getOrderByBusinessId(addOrderDto.getOutBusinessId());
        if(orders!=null){
            return orders;
        }
        orders=new XcOrders();
        orders.setUserId(userId);
        orders.setId(IdWorkerUtils.getInstance().nextId());
        orders.setTotalPrice(addOrderDto.getTotalPrice());
        orders.setCreateDate(LocalDateTime.now());
        orders.setStatus("600001");
        orders.setOrderType("602001");
        orders.setOrderName(addOrderDto.getOrderName());
        orders.setOrderDescrip(addOrderDto.getOrderDescrip());
        orders.setOrderDetail(addOrderDto.getOrderDetail());
        orders.setOutBusinessId(addOrderDto.getOutBusinessId());
        int insert = ordersMapper.insert(orders);
        if(insert<=0){
            XueChengPlusException.cast("添加订单表失败");
        }

        //插入支付记录
        //将前端传入的json转成list
        Long ordersId= orders.getId();
        String orderDetail = addOrderDto.getOrderDetail();
        List<XcOrdersGoods> xcOrdersGoods = JSON.parseArray(orderDetail, XcOrdersGoods.class);
        xcOrdersGoods.forEach(goods->{
            goods.setId(ordersId);
            int insert1 = ordersGoodsMapper.insert(goods);
            if(insert1<=0){
                XueChengPlusException.cast("添加订单明细表失败");
            }
        });

        //生产二维码
        return orders;
    }

    public XcPayRecord createPayRecord(XcOrders orders){

        if(orders==null){
            XueChengPlusException.cast("订单为空");
        }
        if(orders.getStatus().equals("600002")){
            XueChengPlusException.cast("订单已支付");
        }
        XcPayRecord xcPayRecord = new XcPayRecord();
        //生成交易流水号
        xcPayRecord.setPayNo(IdWorkerUtils.getInstance().nextId());
        xcPayRecord.setOrderId(orders.getId());
        xcPayRecord.setOrderName(orders.getOrderName());
        xcPayRecord.setTotalPrice(orders.getTotalPrice());
        xcPayRecord.setCurrency("CNY");
        xcPayRecord.setStatus("601001");
        xcPayRecord.setCreateDate(LocalDateTime.now());
        xcPayRecord.setUserId(orders.getUserId());
        int insert = payRecordMapper.insert(xcPayRecord);
        if(insert<=0){
            XueChengPlusException.cast("插入订单明细表失败");
        }
        return xcPayRecord;
    }
    @Override
    public XcPayRecord getPayRecordByPayno(String payNo) {
        XcPayRecord xcPayRecord = payRecordMapper.selectOne(new LambdaQueryWrapper<XcPayRecord>().eq(XcPayRecord::getPayNo, payNo));
        return xcPayRecord;
    }

    @Override
    public PayRecordDto queryPayResult(String payNo) {
        //调用支付宝接口查询支付结果
        PayStatusDto payStatusDto = queryPayResultFromAlipay(payNo);


        //拿到支付结果更新支付记录表和订单表的支付状态
        orderServiceImpl.saveAliPayStatus(payStatusDto);
        PayRecordDto payRecordDto = new PayRecordDto();
        //返回最新支付记录信息
        XcPayRecord payRecordByPayno = getPayRecordByPayno(payNo);
        BeanUtils.copyProperties(payRecordByPayno,payRecordDto);

        return payRecordDto;
    }
    /**
     * 请求支付宝查询支付结果
     * @param payNo 支付交易号
     * @return 支付结果
     */
    public PayStatusDto queryPayResultFromAlipay(String payNo){
        //========请求支付宝查询支付结果=============
        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.URL, APP_ID, APP_PRIVATE_KEY, "json", AlipayConfig.CHARSET, ALIPAY_PUBLIC_KEY, AlipayConfig.SIGNTYPE); //获得初始化的AlipayClient
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        JSONObject bizContent = new JSONObject();
        bizContent.put("out_trade_no", payNo);
        request.setBizContent(bizContent.toString());
        AlipayTradeQueryResponse response = null;
        try {
            response = alipayClient.execute(request);
            if (!response.isSuccess()) {
                XueChengPlusException.cast("请求支付查询查询失败");
            }
        } catch (AlipayApiException e) {
            log.error("请求支付宝查询支付结果异常:{}", e.toString(), e);
            XueChengPlusException.cast("请求支付查询查询失败");
        }
        //获取支付结果
        String body = response.getBody();
        Map<String,String> map = JSON.parseObject(body, Map.class);
        //解析支付结果
        PayStatusDto payStatusDto = new PayStatusDto();
        payStatusDto.setApp_id(APP_ID);
        payStatusDto.setTrade_status(map.get("trade_status"));
        payStatusDto.setOut_trade_no(payNo);
        payStatusDto.setTrade_no(map.get("trade_no"));
        payStatusDto.setTotal_amount(map.get("total_amount"));

        return payStatusDto;
    }

    /**
     * @description 保存支付宝支付结果
     * @param payStatusDto  支付结果信息
     * @return void
     * @author Mr.M
     * @date 2022/10/4 16:52
     */
    @Transactional
    public void saveAliPayStatus(PayStatusDto payStatusDto) {
        //如果支付成功
        String outTradeNo = payStatusDto.getOut_trade_no();
        XcPayRecord payRecordByPayno = getPayRecordByPayno(outTradeNo);
        if(payRecordByPayno==null){
            XueChengPlusException.cast("找不到支付状态信息");
        }
        Long orderId = payRecordByPayno.getOrderId();
        XcOrders xcOrders = ordersMapper.selectById(orderId);
        if(xcOrders==null){
            XueChengPlusException.cast("找不到相关联的订单信息");
        }

        //支付状态
        String status = payRecordByPayno.getStatus();
        if("601002".equals(status)){
            return ;
        }
        //如果支付成功
        String tradeStatus = payStatusDto.getTrade_status();
        if(tradeStatus.equals("TRADE_SUCCESS")){
            payRecordByPayno.setStatus("601002");
            payRecordByPayno.setOutPayNo(payStatusDto.getTrade_no());
            //第三方支付渠道编号
            payRecordByPayno.setOutPayChannel("Alipay");
            payRecordByPayno.setPaySuccessTime(LocalDateTime.now());
            payRecordMapper.insert(payRecordByPayno);

            //更新支付订单表信息
            xcOrders.setStatus("600002");
            ordersMapper.updateById(xcOrders);

            //保存消息
            MqMessage mqMessage = mqMessageService.addMessage("payresult_notify", xcOrders.getOutBusinessId(), xcOrders.getOrderType(), null);
            //通知消息
            notifyPayResult(mqMessage);
        }


    }

    @Override
    public void notifyPayResult(MqMessage message) {
        String jsonString = JSON.toJSONString(message);
        Long id = message.getId();
        //持久化消息
        Message build = MessageBuilder.withBody(jsonString.getBytes(StandardCharsets.UTF_8)).setDeliveryMode(MessageDeliveryMode.PERSISTENT).build();


        CorrelationData correlationData = new CorrelationData();

        correlationData.getFuture().addCallback(
                result->{
                    if(result.isAck()){
                        //消息发送到交换机
                        log.debug("消息发送成功：{}", jsonString);
                        mqMessageService.completed(id);

                    }else{
                        //消息发送失败
                        log.debug("消息发送失败：{}",jsonString);
                    }
                },
                ex->{
                    //发生异常了
                    log.debug("消息发送异常：{}",jsonString);
                });
        rabbitTemplate.convertAndSend(PayNotifyConfig.PAYNOTIFY_EXCHANGE_FANOUT,"",build,correlationData);
    }


    public XcOrders getOrderByBusinessId(String businessId){
        XcOrders xcOrders = ordersMapper.selectOne(new LambdaQueryWrapper<XcOrders>().eq(XcOrders::getOutBusinessId, businessId));
        return xcOrders;
    }
}
